home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
PROGRAMM
/
PASCAL
/
0921.ZIP
/
MODIFY.ARC
/
MODIF.PAS
Wrap
Pascal/Delphi Source File
|
1988-01-22
|
10KB
|
225 lines
PROGRAM modify4;
{ Version B, 12/23/87. Minor bug fixes, additional comments added
regarding how to deal with headers which fall across the boundaries
of your search buffer.}
{ This is an update of Modify 1.00, which is designed to
allowing quick cloning under Turbo version 3. This now
works under version 4. Address questions and bug reports
to Bob Tolz, Compuserve ID #70475,1071. Original comments for
the modify version 1.00 follow. Please read them with a grain
of salt, given the changes required for upgrading to 4.0}
{---------- Begin Modify 1.00 Comments ------------}
{ PROGRAM Modify_Turbo_COM_File; }
{ For DOS versions of Turbo only }
(*
Purpose of Modify:
Like the popular CLONE.PAS and CLOVER.PAS, Modify provides a method
by which Turbo programmers can allow users to create customized versions
of their programs without recompiling the source.
How it works:
Modify takes advantage of the fact that Turbo stores typed constants
in the code segment. This means that the location of a given typed
constant in a .COM file will always correspond to its offset from CSeg, less
the size of the Program Segment Prefix ($100 bytes). An integer variable
(typed constant) located at CSeg:$0500 while a program is in memory, for
example, can be found by Seek-ing to the 1024th byte (1024 = $400) in the
.COM file. If you were then to write the current value of the integer
variable to disk, the current value would become the default or initial
value. This is what Modify does, essentially, except that it can change
multiple variables in one swoop.
How to use the Modify function:
The demonstration program included here shows how to use Modify, but
I'll explain the procedure briefly anyway:
First, declare all the variables that you want to be able to modify
as typed constants (global) in a single cluster. The cluster should
begin with a "header string", probably the name of the program and perhaps
a version number as well. This will help Modify insure that the .COM
file being modified is the right one. (Be sure that the header string is
unique--if you release an updated version of your Modify-able program,
you should change the header string.) The end of the cluster should be
marked by a one-byte dummy variable, such as "Tail" in the demo program.
In between you can put as many variables as you wish.
Modifying your program is then simple: just call the Modify function
with three parameters: the name of the .COM file, the header string, and
the dummy variable used to mark the end of the cluster. Modify takes
care of everything else, and returns an error code to indicate what
happened. (See the list of return codes, below.)
Modify lacks some of the features of CLONE and CLOVER--it can't make
backup versions of programs, for example--and it is slightly riskier
(in my own programs, I ask the user to confirm that he has a backup
copy of the program before calling Modify). But it is the smallest,
fastest, and simplest routine to clone COM files that I've seen, and
I think that many people will find that its advantages more than
compensate for its disadvantages. (I almost forgot: Modify, like
Clover, works fine for programs with overlays. It will not, however,
work with EXE files created by Turbo Extender. Randy Forgaard is
reportedly working on a simlar routine that will.)
Special thanks to Randy Forgaard for his suggestions, as well as to Bob
Tolz, Bela Lubkin, and James Troutman. Please address all comments,
suggestions, etc. to:
Brian Foley, CompuServe ID #76317,3247.
*)
{---------- End Modify 1.00 Comments ------------}
Uses
tpstring; (*
From Turbo Professional 4.0, produced by TurboPower Software,
to use their Search function. This is not required if you can
create your own routine to search through a buffer for a string
match. I am not employed by Turbo Power Software; I just use
all their products. You can reach them at 408-438-8608, or
through Compuserve ID# 72457,2131.
-RDT *)
TYPE
_FileName = STRING[64];
CONST
{--Cluster of Modify-able variables starts here--}
Headlength = 11;
Head : STRING[11] = 'Modify 4.00';
ProgramName : STRING[64] = 'MODIFY.EXE';
{Used to keep track of name changes.}
Changes : Integer = 0; { Number of times demo has been MODIFY-ed. }
Example : STRING[80] = 'Welcome to MODIFY.EXE.';
Tail : Byte = 0;
{--Cluster ends here--}
FUNCTION Modify(FName : _FileName; VAR Head, Tail) : Byte;
{
Return codes:
0 : FName was modified successfully.
1 : Unable to open FName.
2 : Error reading FName.
3 : Error writing to FName.
5 : Wrong .COM file.
}
CONST filebufferlength = 1024;
{See WARNING!!! below}
VAR
filebuffer : ARRAY[1..filebufferlength] OF Byte;
F : FILE;
Data : ARRAY[1..256] OF Byte ABSOLUTE Head;
Check : STRING[255] ABSOLUTE Head;
Actual : STRING[255];
checksize,
DataSize, modresult,
Result : Integer;
fileoffset, sizeoffile, seekpos : longint;
searchresult : word;
foundmatch : Boolean;
BEGIN
Modresult := 0; { Assume success }
Assign(F, FName);
{$I-}
Reset(F, 1);
{$I+}
IF IOResult <> 0 THEN BEGIN
Modresult := 1; { File wasn't found or couldn't be opened }
END
ELSE BEGIN {level 1}
sizeoffile := FileSize(f);
foundmatch := False;
fileoffset := 0;
searchresult := 0;
seekpos := sizeoffile;
WHILE NOT foundmatch AND NOT((seekpos-filebufferlength) < 0) DO
BEGIN
seekpos := seekpos-filebufferlength;
Seek(f, seekpos);
BlockRead(f, filebuffer, filebufferlength);
searchresult := search(filebuffer, filebufferlength, head, headlength);
(* Search is a function from Turbo Professional 4.0's unit TPSTRING.
If you don't have that package (you should), then you'll need to
write your own routine to search the buffer for the headerstring. *)
IF NOT(searchresult = $FFFF) THEN
BEGIN
foundmatch := True;
fileoffset := seekpos+searchresult;
END;
END;
{WARNING!!! If your header string does not fall ENTIRELY WITHIN
the buffer which was searched, but instead spans two buffer reads,
then the search for your header will fail with this algorithm. The
chances are probably slim given the large size of FILEBUFFERLENGTH,
but if you can't find your header, then look here as the first cause.
You could make this code more bulletproof by forcing the routine to
search around the boundaries of each buffer if the search fails, but
probably the simplest thing to do is change FILEBUFFERLENGTH (either
up or down) by the size of your header string to make sure the header
falls entirely within a buffer}
{$I-}
IF foundmatch THEN
Seek(F, fileoffset);
{$I+}
IF IOResult <> 0 THEN
Modresult := 2 { Error when trying to locate header }
ELSE BEGIN {level 2}
CheckSize := Succ(Ord(Check[0])); { Length of the header string + 1 }
BlockRead(F, Actual, CheckSize, Result);
IF (Result <> CheckSize) (*OR (Actual <> Check)*) THEN BEGIN
IF Result <> CheckSize THEN Modresult := 2 { Read error }
(*{ Actual <> Check } ELSE Modresult := 5; { Header strings don't match }*)
(*This is left over from version 1.0 for Turbo 3.0, it's
unnecessary here since we've specifically searched for the
header string above*)
END
ELSE BEGIN {level 3}
DataSize := Ofs(Tail)-(Ofs(Head)+CheckSize);
{ Now, write everything--from the byte just beyond the header string
to the tail marker--out to disk. File pointer already points to
the first byte after the header string. }
BlockWrite(F, Data[Succ(CheckSize)], DataSize, Result);
IF (Result <> DataSize) THEN Modresult := 3; { Disk write error }
END; {level 3}
END; {level 2}
END; {level 1}
Close(F);
modify := modresult;
END;
BEGIN { Demonstration }
IF ProgramName <> 'MODIFY.EXE' THEN
WriteLn('You''ve changed the program''s name to "', ProgramName, '"');
WriteLn(ProgramName, ' has been changed ', Changes, ' time(s).');
Changes := Succ(Changes);
WriteLn('The current example string is "', Example, '"');
Write('Enter a new one: ');
ReadLn(Example);
IF Modify(ProgramName, Head, Tail) <> 0 THEN BEGIN
{ Assume the problem is simply that the file wasn't found.
This assumption is not a very good one, but OK for the
purposes of the demo program. }
WriteLn('Enter the full file name, or [Return] to exit.');
Write('Full name: ');
ReadLn(ProgramName);
IF ProgramName = '' THEN WriteLn('No changes made.')
ELSE CASE Modify(ProgramName, Head, Tail) OF
0 : WriteLn(ProgramName, ' has been modified successfully.');
1 : WriteLn('Unable to open ', ProgramName);
2 : WriteLn('Error reading from ', ProgramName);
3 : WriteLn('Error writing to ', ProgramName);
5 : WriteLn('Wrong .EXE file: ', ProgramName);
END;
END
ELSE WriteLn(ProgramName, ' has been modified successfully.');
END.